home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / misc / emu / msh-156.lha / dev / devio2.c < prev    next >
C/C++ Source or Header  |  1996-12-22  |  41KB  |  1,617 lines

  1. /*-
  2.  * $Id: devio2.c,v 1.56 1996/12/21 23:34:35 Rhialto Rel $
  3.  * $Log: devio2.c,v $
  4.  * Revision 1.56  1996/12/21  23:34:35  Rhialto
  5.  * Add yet more casts, correct ETD_UPDATE when disk is removed
  6.  * and command retried, correct (a <= b || c = d) mistake.
  7.  *
  8.  * Revision 1.55  1993/12/30  22:45:10    Rhialto
  9.  * Make DMA buffer variable size, depending on largest size needed so far.
  10.  * Remove hardware constants (are now in layout.h).
  11.  * For the new unit #s, the flag value moved to the Unit.
  12.  *
  13.  * Revision 1.54  1993/06/24  04:56:00    Rhialto
  14.  * split read and write functions; always use RAWREAD/RAWWRITE
  15.  * under 2.04+. DICE 2.07.54R.
  16.  *
  17.  * Revision 1.53  92/10/25  02:13:45  Rhialto
  18.  * Add TD_Getgeometry, TD_Eject. Fix some prototypes.
  19.  *  Better read error checking.
  20.  *
  21.  * Revision 1.51  92/04/17  15:42:39  Rhialto
  22.  * Freeze for MAXON3. Change cyl+side units to track units.
  23.  *
  24.  * Revision 1.47  91/11/03  00:49:17  Rhialto
  25.  * Only set WORDSYNC when we want to write, not on read.
  26.  *
  27.  * Revision 1.46  91/10/06  18:27:22  Rhialto
  28.  *
  29.  * Freeze for MAXON
  30.  *
  31.  * Revision 1.44  91/10/02  21:07:42  Rhialto
  32.  * Fix bug that sectors with number 0 are accepted and crash.
  33.  *
  34.  * Revision 1.42  91/06/13  23:47:34  Rhialto
  35.  * DICE conversion
  36.  *
  37.  * Revision 1.40  91/03/03  17:56:00  Rhialto
  38.  * Freeze for MAXON
  39.  *
  40.  * Revision 1.34  91/01/24  00:15:39  Rhialto
  41.  * Use TD_RAWWRITE under AmigaOS 2.0.
  42.  *
  43.  * Revision 1.32  90/11/23  23:55:22  Rhialto
  44.  * Prepare for syslog
  45.  *
  46.  * Revision 1.30  90/06/04  23:18:52  Rhialto
  47.  * Release 1 Patch 3
  48.  *
  49.  * DEVIO.C
  50.  *
  51.  * The messydisk.device code that does the real work.
  52.  *
  53.  * This code is (C) Copyright 1989-1993 by Olaf Seibert. All rights reserved.
  54.  * May not be used or copied without a licence.
  55. -*/
  56.  
  57. #include "device.h"
  58. #include "layout.h"
  59.  
  60. /*#undef DEBUG            */
  61. #ifdef DEBUG
  62. #   include "syslog.h"
  63. #else
  64. #   define    debug(x)
  65. #endif
  66. #define REGISTER
  67.  
  68. Prototype void CMD_Read(struct IOStdReq *ioreq, UNIT *unit);
  69. Prototype void CMD_Write(struct IOStdReq *ioreq, UNIT *unit);
  70. Prototype void TD_Format(struct IOStdReq *ioreq, UNIT *unit);
  71. Prototype void CMD_Reset(struct IOStdReq *ioreq, UNIT *unit);
  72. Prototype void CMD_Update(struct IOStdReq *ioreq, UNIT *unit);
  73. Prototype void CMD_Clear(struct IOStdReq *ioreq, UNIT *unit);
  74. Prototype void TD_Seek(struct IOStdReq *ioreq, UNIT *unit);
  75. Prototype void TD_Changenum(struct IOStdReq *ioreq, UNIT *unit);
  76. Prototype void TD_Addchangeint(struct IOStdReq *ioreq, UNIT *unit);
  77. Prototype void TD_Remchangeint(struct IOStdReq *ioreq, UNIT *unit);
  78. Prototype void TD_Getgeometry(struct IOStdReq *ioreq, UNIT *unit);
  79. Prototype int DevInit(DEV *dev);
  80. Prototype void InitDecoding(byte  *decode);
  81. Prototype long MyDoIO(struct IORequest *req);
  82. Prototype int TDMotorOn(struct IOExtTD *tdreq);
  83. Prototype int TDGetNumTracks(struct IOExtTD *tdreq);
  84. Prototype int TDSeek(UNIT *unit, int track);
  85. Prototype void *GetDrive(struct DiskResourceUnit *drunit);
  86. Prototype void FreeDrive(void);
  87. Prototype int GetTrack(struct IOStdReq *ioreq, int track);
  88. Prototype int CheckChanged(struct IOExtTD *ioreq, UNIT *unit);
  89. Prototype int DevCloseDown(DEV *dev);
  90. Prototype int CheckRequest(struct IOExtTD *ioreq, UNIT *unit);
  91. Prototype UNIT *UnitInit(DEV *dev, ulong UnitNr, ulong Flags);
  92. Prototype int UnitCloseDown(DEV *dev, UNIT *unit);
  93. Prototype __geta4 void DiskChangeHandler(__A1 UNIT *unit);
  94. Prototype void DiskChangeHandler0(void);
  95.  
  96. #ifndef READONLY
  97. Prototype word CalculateGapLength(int sectors);
  98. Prototype int ObtainRawBuffer(DEV *dev, UNIT *unit);
  99. Prototype void FreeRawBuffer(DEV *dev);
  100. Prototype void Internal_Update(struct IOStdReq *ioreq, UNIT *unit);
  101. Prototype __stkargs void EncodeTrack(byte *TrackBuffer, byte *Rawbuffer, word *Crcs, long Cylinder, long Side, long GapLen, long NumSecs, long WriteLen);
  102. /* should become  ... word Cylinder, word Side, word GapLen, word NumSecs */
  103. #endif
  104.  
  105. __stkargs word DataCRC(byte *buffer);
  106. __stkargs void IndexIntCode(void);
  107. __stkargs void DskBlkIntCode(void);
  108. struct tasksig;
  109. int HardwareCommon(DEV *dev, UNIT *unit, struct tasksig *tasksig);
  110. int HardwareRead(DEV *dev, UNIT *unit, struct IOStdReq *ioreq);
  111. int HardwareWrite(DEV *dev, UNIT *unit, struct IOStdReq *ioreq);
  112. int DecodeTrack(DEV *dev, UNIT *unit);
  113. __stkargs word DecodeTrack0(DEV *dev, UNIT *unit);
  114. __stkargs void SafeEnableICR(long bits);
  115. byte DecodeByte(byte *mfmdecode, word mfm);
  116.  
  117. extern __far struct Custom custom;
  118. extern __far struct CIA ciab;
  119.  
  120. struct DiskResource *DRResource;/* Argh! A global variable! */
  121. void *CiaBResource;        /* And yet another! */
  122.  
  123. /*-
  124.  *  The high clock bit in this table is still 0, but it could become
  125.  *  a 1 if the two adjecent data bits are both 0.
  126.  *  In fact, that is the principle of MFM clock bits: make sure that no
  127.  *  two 1 bits are adjecent, but not too many (more than 3) 0 bits either.
  128.  *  So, 0 c 0 -> 0 1 0        (where c is a clock bit to be determined)
  129.  *    0 c 1 -> 0 0 1
  130.  *    1 c 0 -> 1 0 0
  131.  *    1 c 1 -> 1 0 1
  132.  *  The sync pattern, $4489, is %0100 0100 1000 1001
  133.  *                  ~ ~  ~ ~  ~ ~  ~ ~ -> %1010 0001 -> $A1
  134.  *  also follows the rules, but won't be formed by encoding $A1...
  135.  *  Since the bytes are written high bit first, the unknown clock bit
  136.  *  (for encoded nybbles 0-7, high bit 0) will become a 1 if the preceding
  137.  *  byte was even (with low bit 0).
  138.  *  So, the clock bit is the NOR of the two data bits.
  139. -*/
  140.  
  141. byte        MfmEncode[16] = {
  142.     0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,
  143.     0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55
  144. };
  145.  
  146. word        MfmEncodeWord[256];
  147.  
  148. #define DSKDMAEN    (1<<15)
  149. #define DSKWRITE    (1<<14)
  150.  
  151.  
  152. /* INDENT ON */
  153.  
  154. struct tasksig {
  155.     struct Task *task;
  156.     ulong signal;
  157. };
  158.  
  159. HardwareCommon(dev, unit, tasksig)
  160. DEV           *dev;
  161. UNIT           *unit;
  162. struct tasksig *tasksig;
  163. {
  164.     tasksig->task = FindTask(NULL);
  165.     tasksig->signal = 1L << unit->mu_DmaSignal;
  166.  
  167.     unit->mu_DRUnit.dru_DiscBlock.is_Data = (APTR) tasksig;
  168.  
  169.     /* Clear signal bit */
  170.     SetSignal(0L, tasksig->signal);
  171.  
  172.     /* Allocate drive and install index and block interrupts */
  173.     GetDrive(&unit->mu_DRUnit);
  174.  
  175.     /* Clear any disk interrupts that might be pending (should not be needed) */
  176.     custom.intreq = INTF_DSKBLK;
  177.  
  178.     /* Select correct drive and side */
  179.     ciab.ciaprb = 0xff & ~CIAF_DSKMOTOR;    /* See hardware manual p244 (2nd ed: p229) */
  180.     ciab.ciaprb = 0xff & ~CIAF_DSKMOTOR
  181.                & ~(CIAF_DSKSEL0 << unit->mu_UnitNr)
  182.                & ~(TRK2SIDE(unit->mu_CurrentTrack) << CIAB_DSKSIDE);
  183.  
  184.     /* Set up disk parameters */
  185.  
  186. /*
  187.  * This is the adkcon setup: MFM mode, (wordsync), no MSBsync, fast mode.
  188.  * The precomp is 0 nanoseconds for the outer half of the disk, 120 for
  189.  * the rest.
  190.  */
  191.     {
  192.     REGISTER word adk;
  193.  
  194.     custom.adkcon = ADKF_PRECOMP1|ADKF_PRECOMP0|ADKF_MSBSYNC|ADKF_WORDSYNC;
  195.  
  196.     adk = ADKF_SETCLR|ADKF_MFMPREC|ADKF_FAST;
  197.  
  198.     /* Are we on the inner half ? */
  199.     if (unit->mu_CurrentTrack > (unit->mu_NumTracks >> 1)) {
  200.         adk |= ADKF_PRECOMP0;
  201.     }
  202.     custom.adkcon = adk;
  203.     }
  204.  
  205.     /* Set up disk buffer address */
  206.     custom.dskpt = (APTR) dev->md_Rawbuffer;
  207.  
  208.     /* Enable disk DMA */
  209.     custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_DISK;
  210. }
  211.  
  212. int
  213. HardwareRead(dev, unit, ioreq)
  214. DEV           *dev;
  215. REGISTER UNIT  *unit;
  216. struct IOStdReq *ioreq;
  217. {
  218.     struct tasksig  tasksig;
  219.  
  220.     debug(("Disk buffer is at %lx\n", dev->md_Rawbuffer));
  221.  
  222. #ifndef NONCOMM
  223.     if (dev->md_System_2_04) {
  224.     REGISTER struct IOExtTD *tdreq = unit->mu_DiskIOReq;
  225.  
  226.     tdreq->iotd_Req.io_Command = TD_RAWREAD;
  227.     tdreq->iotd_Req.io_Flags = IOTDF_WORDSYNC;
  228.     tdreq->iotd_Req.io_Length = unit->mu_ReadLen;
  229.     tdreq->iotd_Req.io_Data = (APTR)dev->md_Rawbuffer;
  230.     if ((unit->mu_OpenFlags & IOMDF_40TRACKS) &&
  231.         (unit->mu_NumTracks == TRACKS(80))) {
  232.         tdreq->iotd_Req.io_Offset = 2 * unit->mu_CurrentTrack -
  233.                     TRK2SIDE(unit->mu_CurrentTrack);
  234.     } else {
  235.         tdreq->iotd_Req.io_Offset = unit->mu_CurrentTrack;
  236.     }
  237.     debug(("TDRawRead %ld\n", tdreq->iotd_Req.io_Offset));
  238.     MyDoIO((struct IORequest *)tdreq);
  239.  
  240.     return tdreq->iotd_Req.io_Error;
  241.     }
  242. #endif
  243.  
  244.     HardwareCommon(dev, unit, &tasksig);
  245.  
  246.     /* Enable Wordsync and set the sync word */
  247.     custom.adkcon = ADKF_SETCLR | ADKF_WORDSYNC;
  248.     custom.dsksync = SYNC;
  249.  
  250.     /* Do the same as the disk index interrupt would */
  251.     custom.dsklen = DSKDMAOFF;
  252.     custom.dsklen = (unit->mu_ReadLen >> 1) | DSKDMAEN;
  253.     custom.dsklen = (unit->mu_ReadLen >> 1) | DSKDMAEN;
  254.  
  255.     custom.intena = INTF_SETCLR | INTF_DSKBLK;
  256.  
  257.     Wait(tasksig.signal);
  258.  
  259.     FreeDrive();
  260.     return TDERR_NoError;
  261. }
  262.  
  263. int
  264. HardwareWrite(dev, unit, ioreq)
  265. DEV           *dev;
  266. REGISTER UNIT  *unit;
  267. struct IOStdReq *ioreq;
  268. {
  269.     struct tasksig  tasksig;
  270.  
  271.     debug(("Disk buffer is at %lx\n", dev->md_Rawbuffer));
  272.  
  273. #ifndef NONCOMM
  274.     if (dev->md_System_2_04) {
  275.     REGISTER struct IOExtTD *tdreq = unit->mu_DiskIOReq;
  276.  
  277.     tdreq->iotd_Req.io_Command = TD_RAWWRITE;
  278.     tdreq->iotd_Req.io_Flags = IOTDF_INDEXSYNC;
  279.     tdreq->iotd_Req.io_Length = unit->mu_WriteLen;
  280.     tdreq->iotd_Req.io_Data = (APTR)dev->md_Rawbuffer;
  281.     if ((unit->mu_OpenFlags & IOMDF_40TRACKS) &&
  282.         (unit->mu_NumTracks == TRACKS(80))) {
  283.         tdreq->iotd_Req.io_Offset = 2 * unit->mu_CurrentTrack -
  284.                     TRK2SIDE(unit->mu_CurrentTrack);
  285.     } else {
  286.         tdreq->iotd_Req.io_Offset = unit->mu_CurrentTrack;
  287.     }
  288.     debug(("TDRawWrite %ld\n", tdreq->iotd_Req.io_Offset));
  289.     MyDoIO((struct IORequest *)tdreq);
  290.  
  291.     return tdreq->iotd_Req.io_Error;
  292.     }
  293. #endif
  294.  
  295.     HardwareCommon(dev, unit, &tasksig);
  296.     unit->mu_DRUnit.dru_Index.is_Data = (APTR)
  297.     ((unit->mu_WriteLen >> 1)| DSKDMAEN | DSKWRITE);
  298.  
  299.     /* Enable disk index interrupt to start the whole thing. */
  300.     SafeEnableICR(CIAICRF_FLG);
  301.  
  302.     Wait(tasksig.signal);
  303.  
  304.     FreeDrive();
  305.     return TDERR_NoError;
  306. }
  307.  
  308.  
  309. #if 0
  310. #define ID_ADDRESS_MARK     0xFE
  311. #define MFM_ID            0x5554
  312. #define DATA_ADDRESS_MARK   0xFB
  313. #define MFM_DATA        0x5545
  314.  
  315. byte DecodeByte(byte *mfmdecode, word mfm);
  316.  
  317. byte
  318. DecodeByte(mfmdecode, mfm)
  319. byte *mfmdecode;
  320. word mfm;
  321. {
  322.     return mfmdecode[(byte)mfm & 0x7F] |
  323.        mfmdecode[(byte)(mfm >> 8) & 0x7F] << 4;
  324. }
  325.  
  326. int
  327. DecodeTrack(dev, unit)
  328. DEV           *dev;
  329. UNIT           *unit;
  330. {
  331.     REGISTER word  *rawbuf = (word *)dev->md_Rawbuffer; /*  a2 */
  332.     word       *rawend = (word *)
  333.                  ((byte *)rawbuf + unit->mu_ReadLen -
  334.                   (MS_BPS+2)*sizeof(word));
  335.     byte       *trackbuf = unit->mu_TrackBuffer;
  336.     REGISTER byte  *decode = dev->md_MfmDecode;     /*  a3 */
  337.     word       *oldcrc = unit->mu_CrcBuffer;
  338.     REGISTER byte  *secptr;                /*  a4 */
  339.     long        sector;
  340.     word        numsecs;
  341.     REGISTER long   numbytes;                /*  d3 */
  342.     word        maxsec;
  343.  
  344. #define Len    ((byte *)rawbuf - dev->md_Rawbuffer)
  345.     maxsec = 0;
  346.  
  347.     for (numsecs = 0; numsecs < MS_SPT_MAX; numsecs++) {
  348.     /*
  349.      *  First try to find a sector id.
  350.      */
  351. find_id:
  352.     while (*rawbuf != SYNC) {
  353.         if (++rawbuf >= rawend) {
  354.         debug(("id start, EOT %4lx\n", (long)Len));
  355.         goto end;
  356.         }
  357.     }
  358.     while (*rawbuf == SYNC) {
  359.         rawbuf++;
  360.     }
  361.     if (*rawbuf++ != MFM_ID) {
  362.         debug(("No ID (%4lx), %4lx\n", (long)rawbuf[-1], (long)Len));
  363.         goto find_id;
  364.     }
  365.  
  366.     sector = DecodeByte(decode, *rawbuf++);
  367.     if (TRACKS(sector) != unit->mu_CurrentTrack) {
  368.         debug(("Cylinder error?? %ld\n", sector));
  369.         goto find_id;
  370.     }
  371.     sector = DecodeByte(decode, *rawbuf++);
  372.     if (sector != TRK2SIDE(unit->mu_CurrentTrack)) {
  373.         debug(("Side error?? %ld\n", sector));
  374.         goto find_id;
  375.     }
  376.     if (rawbuf >= rawend) {
  377.         debug(("id end, EOT %4lx\n", (long)Len));
  378.         goto end;
  379.     }
  380.     sector = DecodeByte(decode, *rawbuf++);
  381.     debug(("#%2ld %4x, ", sector, (long)Len-0xC));
  382.     if (sector > MS_SPT_MAX || sector < 1) {
  383.         debug(("Bogus sector number)\n"));
  384.         goto find_id;
  385.     }
  386.     if (sector > maxsec)
  387.         maxsec = sector;
  388.     sector--;        /* Normalize sector number */
  389.  
  390.     /*
  391.      *  Then find the data block.
  392.      */
  393. find_data:
  394.     while (*rawbuf != SYNC) {
  395.         if (++rawbuf >= rawend) {
  396.         debug(("data start, EOT %4lx\n", (long)Len));
  397.         return 0; /* TDERR_TooFewSecs; */
  398.         }
  399.     }
  400.     while (*rawbuf == SYNC) {
  401.         rawbuf++;
  402.     }
  403.     if (*rawbuf++ != MFM_DATA) {
  404.         debug(("No Data (%4lx), %4lx\n", (long)rawbuf[-1], (long)Len));
  405.         goto find_id;
  406.     }
  407.     debug(("%4lx, ", (long)Len-8));
  408.  
  409.     if (rawbuf >= rawend) {
  410.         debug(("short data, EOT %4lx\n", (long)Len));
  411.         goto end;
  412.     }
  413.     secptr = trackbuf + MS_BPS * sector;
  414.     for (numbytes = 0; numbytes < MS_BPS; numbytes++) {
  415.         *secptr++ = DecodeByte(decode, *rawbuf++);
  416.     }
  417.     debug(("%4lx\n", (long)Len));
  418.     oldcrc[sector]    = DecodeByte(decode, *rawbuf++) << 8;
  419.     oldcrc[sector] |= DecodeByte(decode, *rawbuf++);
  420.     unit->mu_SectorStatus[sector] = unit->mu_InitSectorStatus;
  421.     }
  422.  
  423. end:
  424.     if (maxsec == 0)
  425.     return TDERR_TooFewSecs;
  426.  
  427. #ifndef READONLY
  428.     /*
  429.      * If we read the very first track, we adjust our notion about the
  430.      * number of sectors on each track. This is the only track we can
  431.      * accurately find if this number is unknown. Let's hope that the first
  432.      * user of this disk starts reading it here.
  433.      */
  434.     if (unit->mu_CurrentTrack == 0) {
  435.     unit->mu_SectorsPerTrack = maxsec;
  436.     }
  437.     unit->mu_CurrentSectors = maxsec;
  438.     debug(("%ld sectors\n", (long)unit->mu_SectorsPerTrack));
  439. #endif
  440.  
  441.     return 0;
  442.  
  443. #undef Len
  444. }
  445. #else    /* Use assembly */
  446.  
  447. int
  448. DecodeTrack(dev, unit)
  449. DEV           *dev;
  450. UNIT           *unit;
  451. {
  452.     word maxsec;
  453.  
  454.     maxsec = DecodeTrack0(dev, unit);
  455.  
  456.     if (maxsec == 0)
  457.     return TDERR_TooFewSecs;
  458.  
  459. #ifndef READONLY
  460.     /*
  461.      * If we read the very first track, we adjust our notion about the
  462.      * number of sectors on each track. This is the only track we can
  463.      * accurately find if this number is unknown. Let's hope that the first
  464.      * user of this disk starts reading it here.
  465.      */
  466.     if (unit->mu_CurrentTrack == 0) {
  467.     unit->mu_SectorsPerTrack = maxsec;
  468.     }
  469.     unit->mu_CurrentSectors = maxsec;
  470.     debug(("%ld sectors\n", (long)unit->mu_SectorsPerTrack));
  471. #endif
  472.  
  473.     return 0;
  474. }
  475.  
  476. #endif    /* using assembly */
  477.  
  478. /*
  479.  * Initialize the ibm mfm decoding table
  480.  */
  481.  
  482. void
  483. InitDecoding(decode)
  484. REGISTER byte  *decode;
  485. {
  486.     REGISTER int    i;
  487.  
  488.     i = 0;
  489.     do {
  490.     decode[i] = 0xff;
  491.     } while (++i < 128);
  492.  
  493.     i = 0;
  494.     do {
  495.     decode[MfmEncode[i]] = i;
  496.     } while (++i < 0x10);
  497.  
  498.     /* This does not belong here!! */
  499.     for (i = 0; i < 256; i++) {
  500.     MfmEncodeWord[i] = MfmEncode[i & 0x0F] | MfmEncode[i >> 4] << 8 |
  501.                ((i & 0x18) ? 0 : 0x80);
  502.     /*           %0001 1000  %1000 0000 */
  503.     }
  504. }
  505.  
  506. #ifndef NONCOMM
  507. long
  508. MyDoIO(req)
  509. REGISTER struct IORequest *req;
  510. {
  511.     req->io_Flags |= IOF_QUICK;
  512.     BeginIO(req);
  513.     return WaitIO(req);
  514. }
  515. #endif
  516.  
  517. /*
  518.  * Switch the drive motor on. Return previous state. Don't use this when
  519.  * you have allocated the disk via GetDrive().
  520.  */
  521.  
  522. int
  523. TDMotorOn(tdreq)
  524. REGISTER struct IOExtTD *tdreq;
  525. {
  526.     debug(("TDMotorOn "));
  527.     tdreq->iotd_Req.io_Command = TD_MOTOR;
  528.     tdreq->iotd_Req.io_Length = 1;
  529.     DoIO((struct IORequest *)tdreq);
  530.     debug(("was %ld\n", tdreq->iotd_Req.io_Actual));
  531.  
  532.     return tdreq->iotd_Req.io_Actual;
  533. }
  534.  
  535. /*
  536.  * Get the number of tracks the drive is capable of using. This is
  537.  * NUMHEADS times the number of cylinders.
  538.  */
  539.  
  540. int
  541. TDGetNumTracks(tdreq)
  542. REGISTER struct IOExtTD *tdreq;
  543. {
  544.     tdreq->iotd_Req.io_Command = TD_GETNUMTRACKS;
  545.     DoIO((struct IORequest *)tdreq);
  546.  
  547.     return tdreq->iotd_Req.io_Actual;
  548. }
  549.  
  550. /*
  551.  * Seek the drive to the indicated track. Use the trackdisk.device for
  552.  * ease. Don't use this when you have allocated the disk via GetDrive().
  553.  * The tracknumber is in Amiga units. We don't care what side of the disk
  554.  * we end up on ;-) so we discard the side number information.
  555.  */
  556.  
  557. int
  558. TDSeek(unit, track)
  559. UNIT       *unit;
  560. int        track;
  561. {
  562.  
  563.     REGISTER struct IOExtTD *tdreq = unit->mu_DiskIOReq;
  564.  
  565.     debug(("TDSeek track %ld\n", (long)track));
  566.  
  567.     tdreq->iotd_Req.io_Command = TD_SEEK;
  568.     tdreq->iotd_Req.io_Offset = TRK2CYL(track) * (TD_SECTOR * NUMSECS * NUMHEADS);
  569.     if (unit->mu_DiskState & STATEF_HIGHDENSITY)
  570.     tdreq->iotd_Req.io_Offset *= 2;
  571.     if ((unit->mu_OpenFlags & IOMDF_40TRACKS) && (unit->mu_NumTracks == TRACKS(80)))
  572.     tdreq->iotd_Req.io_Offset *= 2;
  573.     DoIO((struct IORequest *)tdreq);
  574.  
  575.     return tdreq->iotd_Req.io_Error;
  576. }
  577.  
  578. void           *
  579. GetDrive(drunit)
  580. REGISTER struct DiskResourceUnit *drunit;
  581. {
  582.     REGISTER void  *LastDriver;
  583.  
  584.     debug(("GetDrive: "));
  585.     for (;;) {
  586.     drunit->dru_Message.mn_Node.ln_Type = NT_MESSAGE;
  587.     LastDriver = GetUnit(drunit);
  588.  
  589.     debug(("LastDriver %08lx\n", LastDriver));
  590.     if (LastDriver) {
  591.         return LastDriver;
  592.     } else {
  593.         while (drunit->dru_Message.mn_Node.ln_Type != NT_REPLYMSG)
  594.         Wait(1L << drunit->dru_Message.mn_ReplyPort->mp_SigBit);
  595.         Remove(&drunit->dru_Message.mn_Node);
  596.         debug(("GetDrive: Retry\n"));
  597.     }
  598.     }
  599. }
  600.  
  601. void
  602. FreeDrive()
  603. {
  604.     GiveUnit();
  605. }
  606.  
  607. int
  608. GetTrack(ioreq, track)
  609. struct IOStdReq *ioreq;
  610. int        track;
  611. {
  612.     REGISTER int    i;
  613.     DEV        *dev;
  614.     REGISTER UNIT  *unit;
  615.  
  616.     debug(("GetTrack %ld\n", (long)track));
  617.     dev = (DEV *) ioreq->io_Device;
  618.     unit = (UNIT *) ioreq->io_Unit;
  619.  
  620.     if (track != unit->mu_CurrentTrack) {
  621. #ifndef READONLY
  622.     Internal_Update(ioreq, unit);
  623. #endif
  624.     for (i = MS_SPT_MAX-1; i >= 0; i--) {
  625.         unit->mu_SectorStatus[i] = TDERR_NoSecHdr;
  626.     }
  627.  
  628.     TDMotorOn(unit->mu_DiskIOReq);
  629.     if (TDSeek(unit, track)) {
  630.         debug(("Seek error\n"));
  631.         return ioreq->io_Error = IOERR_BADLENGTH;
  632.     }
  633.     unit->mu_CurrentTrack = track;
  634.     ObtainSemaphore(&dev->md_HardwareUse);
  635.     ObtainRawBuffer(dev, unit);
  636.     HardwareRead(dev, unit, ioreq);
  637.     i = DecodeTrack(dev, unit);
  638.     ReleaseSemaphore(&dev->md_HardwareUse);
  639.     debug(("DecodeTrack returns %ld\n", (long)i));
  640.  
  641.     if (i != 0) {
  642.         unit->mu_CurrentTrack = -1;
  643.         return i;
  644.     }
  645.     }
  646.  
  647.     return 0;
  648. }
  649.  
  650. /*
  651.  * Test if it is changed
  652.  */
  653.  
  654. int
  655. CheckChanged(ioreq, unit)
  656. struct IOExtTD *ioreq;
  657. REGISTER UNIT  *unit;
  658. {
  659.     if ((ioreq->iotd_Req.io_Command & TDF_EXTCOM) &&
  660.     ioreq->iotd_Count < unit->mu_ChangeNum) {
  661. diskchanged:
  662.     ioreq->iotd_Req.io_Error = TDERR_DiskChanged;
  663. error:
  664.     return 1;
  665.     }
  666.     return 0;
  667. }
  668.  
  669. /*
  670.  * Copy the io_Flags to md_OpenFlags, unless the FIXFLAGS bit is set.
  671.  * This is because we must be able to modify this pesky 40-track
  672.  * mode.
  673.  */
  674.  
  675. void
  676. UpdateOpenFlags(struct IOStdReq *ioreq, UNIT *unit)
  677. {
  678.     if ((unit->mu_OpenFlags & IOMDF_FIXFLAGS) == 0) {
  679.     unit->mu_OpenFlags = ioreq->io_Flags & ~IOMDF_FIXFLAGS;
  680.     }
  681. }
  682.  
  683. /*
  684.  * Determine the type of the connected drive.
  685.  * The relevant return values are DRIVE3_5_150RPM (21 sectors max)
  686.  * and DRIVE3_5 or DRIVE5_25 (10 sectors max).
  687.  */
  688.  
  689. void
  690. CheckDriveType(UNIT *unit)
  691. {
  692.     struct IOExtTD *tdreq;
  693.  
  694.     tdreq = unit->mu_DiskIOReq;
  695.     tdreq->iotd_Req.io_Command = TD_GETDRIVETYPE;
  696.     DoIO((struct IORequest *)tdreq);
  697.     if (tdreq->iotd_Req.io_Actual == DRIVE3_5_150RPM) {
  698.     /* HD drive and HD disk */
  699.     debug(("HD disk\n"));
  700.     unit->mu_DiskState |= STATEF_HIGHDENSITY;
  701.     unit->mu_ReadLen  = 2 * RLEN;
  702.     unit->mu_WriteLen = 2 * WLEN;
  703.     } else {
  704.     /* DD drive or DD disk */
  705.     debug(("normal disk\n"));
  706.     unit->mu_DiskState &= ~STATEF_HIGHDENSITY;
  707.     unit->mu_ReadLen  = RLEN;
  708.     unit->mu_WriteLen = WLEN;
  709.     }
  710. }
  711.  
  712. /*
  713.  * Test if we can read or write the disk. Is it inserted and writable?
  714.  * What kind of drive do we have (HD or normal)?
  715.  */
  716.  
  717. int
  718. CheckRequest(ioreq, unit)
  719. struct IOExtTD *ioreq;
  720. REGISTER UNIT  *unit;
  721. {
  722.     REGISTER struct IOExtTD *tdreq;
  723.  
  724.     UpdateOpenFlags(&ioreq->iotd_Req, unit);
  725.  
  726.  
  727.     if ((ioreq->iotd_Req.io_Command & TDF_EXTCOM) &&
  728.     ioreq->iotd_Count < unit->mu_ChangeNum) {
  729. diskchanged:
  730.     ioreq->iotd_Req.io_Error = TDERR_DiskChanged;
  731.     debug(("CheckRequest cmd=%04lx iotd_Count=%ld mu_ChangeNum=%ld -> TDERR_DiskChanged\n",
  732.            ioreq->iotd_Req.io_Command, ioreq->iotd_Count, unit->mu_ChangeNum));
  733.     return TDERR_DiskChanged;
  734.     }
  735.  
  736. #if 0
  737.     if (ioreq->iotd_Req.io_Offset + ioreq->iotd_Req.io_Length >
  738.     (unit->mu_NumTracks * MS_SPT * MS_BPS)) {
  739.     ioreq->iotd_Req.io_Error = IOERR_BADLENGTH;
  740.     goto error;
  741.     }
  742. #endif
  743.  
  744.     tdreq = unit->mu_DiskIOReq;
  745.  
  746.     if (unit->mu_DiskState & STATEF_UNKNOWN) {
  747.     tdreq->iotd_Req.io_Command = TD_PROTSTATUS;
  748.     DoIO((struct IORequest *)tdreq);
  749.     if (tdreq->iotd_Req.io_Error == 0) {
  750.         if (tdreq->iotd_Req.io_Actual == 0) {
  751.         unit->mu_DiskState = STATEF_PRESENT | STATEF_WRITABLE;
  752.         } else
  753.         unit->mu_DiskState = STATEF_PRESENT;
  754.     } else
  755.         unit->mu_DiskState = 0;
  756.  
  757.     /* Check drive type */
  758.     CheckDriveType(unit);
  759.     }
  760.     if (!(unit->mu_DiskState & STATEF_PRESENT))
  761.     goto diskchanged;
  762.  
  763.     /*
  764.      * Check _WRITE, _UPDATE, _FORMAT
  765.      */
  766.     if (STRIP(ioreq->iotd_Req.io_Command) != CMD_READ) {
  767.     if (!(unit->mu_DiskState & STATEF_WRITABLE)) {
  768.         ioreq->iotd_Req.io_Error = TDERR_WriteProt;
  769.         return TDERR_WriteProt;
  770.     }
  771.     }
  772.     return 0;
  773. }
  774.  
  775.  
  776. /*
  777.  * Read zero or more sectors from the disk and copy them into the user's
  778.  * buffer.
  779.  */
  780.  
  781. void
  782. CMD_Read(ioreq, unit)
  783. REGISTER struct IOStdReq *ioreq;
  784. REGISTER UNIT  *unit;
  785. {
  786.     int         track;
  787.     int         sector;
  788.     byte       *userbuf;
  789.     long        length;
  790.     long        offset;
  791.     byte       *diskbuf;
  792.     int         retrycount;
  793.     int         error;
  794.  
  795.     debug(("CMD_Read "));
  796.     userbuf = (byte *) ioreq->io_Data;
  797.     length = ioreq->io_Length / MS_BPS;        /* Sector count */
  798.     offset = ioreq->io_Offset / MS_BPS;        /* Sector number */
  799.     debug(("userbuf %08lx off %ld len %ld ", userbuf, offset, length));
  800.  
  801.     track = offset / unit->mu_SectorsPerTrack;
  802.     sector = offset % unit->mu_SectorsPerTrack;       /* 0..8 or 9 */
  803.     debug(("Tr=%ld Si=%ld Se=%ld\n", (long)track / MS_NSIDES, (long)track % MS_NSIDES, (long)sector));
  804.  
  805.     ioreq->io_Actual = 0;
  806.     error = TDERR_NoError;
  807.  
  808.     if ((length <= 0) || (error = CheckRequest((struct IOExtTD *)ioreq, unit)))
  809.     goto end;
  810.  
  811.     retrycount = 0;
  812.     diskbuf = unit->mu_TrackBuffer + MS_BPS * sector;
  813. gettrack:
  814.     error = GetTrack(ioreq, track);
  815.  
  816.     while (error == TDERR_NoError) {
  817.     /*
  818.      * Have we ever checked this CRC?
  819.      */
  820.     if (unit->mu_SectorStatus[sector] == CRC_UNCHECKED) {
  821.         /*
  822.          * Do it now. If it mismatches, remember that for later.
  823.          */
  824.         if (unit->mu_CrcBuffer[sector] != DataCRC(diskbuf)) {
  825.         debug(("%ld: %04lx, now %04lx\n", (long)sector, (long)unit->mu_CrcBuffer[sector], (long)DataCRC(diskbuf)));
  826.         unit->mu_SectorStatus[sector] = TDERR_BadSecSum;
  827.         } else
  828.         unit->mu_SectorStatus[sector] = TDERR_NoError;
  829.     }
  830.     if (unit->mu_SectorStatus[sector] > TDERR_NoError) {
  831.         if (++retrycount < 3) {
  832.         unit->mu_CurrentTrack = -1;
  833.         goto gettrack;
  834.         }
  835.         error = unit->mu_SectorStatus[sector];
  836.         goto end;        /* Don't use this sector anymore... */
  837.     }
  838.     retrycount = 0;
  839.     CopyMem(diskbuf, userbuf, (long) MS_BPS);
  840.     ioreq->io_Actual += MS_BPS;
  841.     if (--length <= 0)
  842.         break;
  843.     userbuf += MS_BPS;
  844.     diskbuf += MS_BPS;
  845.     if (++sector >= unit->mu_SectorsPerTrack) {
  846.         sector = 0;
  847.         diskbuf = unit->mu_TrackBuffer;
  848.         if (++track >= unit->mu_NumTracks) {
  849.         /* ioreq->io_Error = IOERR_BADLENGTH; */
  850.         goto end;
  851.         }
  852.         error = GetTrack(ioreq, track);
  853.     }
  854.     }
  855.  
  856. end:
  857.     ioreq->io_Error = error;
  858.     TermIO(ioreq);
  859. }
  860.  
  861. #ifdef READONLY
  862.  
  863. void
  864. CMD_Write(ioreq, unit)
  865. REGISTER struct IOStdReq *ioreq;
  866. UNIT           *unit;
  867. {
  868.     ioreq->io_Error = TDERR_NotSpecified;
  869.     TermIO(ioreq);
  870. }
  871.  
  872. void
  873. TD_Format(ioreq, unit)
  874. REGISTER struct IOStdReq *ioreq;
  875. UNIT           *unit;
  876. {
  877.     ioreq->io_Error = TDERR_NotSpecified;
  878.     TermIO(ioreq);
  879. }
  880.  
  881. #endif
  882.  
  883. void
  884. CMD_Reset(ioreq, unit)
  885. struct IOStdReq *ioreq;
  886. UNIT           *unit;
  887. {
  888.     unit->mu_CurrentTrack = -1;
  889.     unit->mu_TrackChanged = 0;
  890.     TermIO(ioreq);
  891. }
  892.  
  893. void
  894. CMD_Update(ioreq, unit)
  895. struct IOStdReq *ioreq;
  896. REGISTER UNIT  *unit;
  897. {
  898. #ifndef READONLY
  899.     if (unit->mu_TrackChanged && !CheckRequest((struct IOExtTD *)ioreq, unit))
  900.     Internal_Update(ioreq, unit);
  901. #endif
  902.     TermIO(ioreq);
  903. }
  904.  
  905. void
  906. CMD_Clear(ioreq, unit)
  907. struct IOStdReq *ioreq;
  908. UNIT           *unit;
  909. {
  910.     if (!CheckChanged((struct IOExtTD *)ioreq, unit)) {
  911.     unit->mu_CurrentTrack = -1;
  912.     unit->mu_TrackChanged = 0;
  913.     }
  914.     TermIO(ioreq);
  915. }
  916.  
  917. void
  918. TD_Seek(ioreq, unit)
  919. struct IOStdReq *ioreq;
  920. UNIT           *unit;
  921. {
  922.     if (!CheckChanged((struct IOExtTD *)ioreq, unit)) {
  923.     int        track;
  924.  
  925.     UpdateOpenFlags(ioreq, unit);
  926.     track = (ioreq->io_Offset / MS_BPS) / unit->mu_SectorsPerTrack;
  927.     TDSeek(unit, track);
  928.     }
  929.     TermIO(ioreq);
  930. }
  931.  
  932. /*
  933.  * Ask the trackdisk.device for the answer, but keep a local copy.
  934.  */
  935.  
  936. void
  937. TD_Changenum(ioreq, unit)
  938. struct IOStdReq *ioreq;
  939. UNIT           *unit;
  940. {
  941.     REGISTER struct IOStdReq *req;
  942.  
  943.     req = &unit->mu_DiskIOReq->iotd_Req;
  944.     req->io_Command = TD_CHANGENUM;
  945.     DoIO((struct IORequest *)req);
  946.  
  947. #ifdef DEBUG
  948.     if (unit->mu_ChangeNum != req->io_Actual)
  949.     debug(("Our changenum %d != trackdisk's %d!\n",
  950.            unit->mu_ChangeNum, req->io_Actual));
  951. #endif
  952.     unit->mu_ChangeNum = req->io_Actual;
  953.     ioreq->io_Actual = req->io_Actual;
  954.     TermIO(ioreq);
  955. }
  956.  
  957. int
  958. DevInit(dev)
  959. REGISTER DEV   *dev;
  960. {
  961.     debug(("Open disk.resource\n"));
  962.     if (!(DRResource = OpenResource(DISKNAME)))
  963.     goto abort;
  964.  
  965.     debug(("Open cia.resource\n"));
  966.     if (!(CiaBResource = OpenResource(CIABNAME)))
  967.     goto abort;
  968.  
  969.  
  970.     debug(("init decoding\n"));
  971.     InitDecoding(dev->md_MfmDecode);
  972.     debug(("init semaphore\n"));
  973.     InitSemaphore(&dev->md_HardwareUse);
  974.     debug(("done init\n"));
  975.     return 1;            /* Initializing succeeded */
  976.  
  977. abort:
  978.     return DevCloseDown(dev);
  979. }
  980.  
  981. int
  982. DevCloseDown(dev)
  983. DEV           *dev;
  984. {
  985. #ifndef READONLY
  986.     FreeRawBuffer(dev);
  987. #endif
  988.     return 0;            /* Now unitialized */
  989. }
  990.  
  991. #ifndef READONLY
  992. /*
  993.  * Calculate the length between the sectors, given the length of the track
  994.  * and the number of sectors that must fit on it.
  995.  * The proper formula would be
  996.  * (((TLEN/2) - INDEXLEN) / sectors) - BLOCKLEN;
  997.  */
  998.  
  999. word
  1000. CalculateGapLength(sectors)
  1001. int        sectors;
  1002. {
  1003.     /*return (sectors == 10) ? DATAGAP3_10 : DATAGAP3_9;*/
  1004.     /*return (sectors == 10 || sectors == 20) ? DATAGAP3_10 : DATAGAP3_9;*/
  1005.     int         tmp;
  1006.  
  1007.     tmp = (sectors <= 10)? TLEN / 2 : 2 * (TLEN / 2);
  1008.  
  1009.     tmp = ((tmp - INDEXLEN) / sectors) - BLOCKLEN;
  1010.     if (tmp > DATAGAP3_9)
  1011.     tmp = DATAGAP3_9;
  1012.  
  1013.     return tmp;
  1014. }
  1015. #endif
  1016.  
  1017. UNIT           *
  1018. UnitInit(DEV *dev, ulong UnitNr, ulong Flags)
  1019. {
  1020.     REGISTER UNIT  *unit;
  1021.     struct Task    *task;
  1022.     struct IOStdReq *dcr;
  1023.     struct IOExtTD *tdreq;
  1024.  
  1025.     unit = AllocMem((long) sizeof (UNIT), MEMF_PUBLIC | MEMF_CLEAR);
  1026.     if (unit == NULL)
  1027.     return NULL;
  1028.  
  1029.     if (!(unit->mu_TrackBuffer = AllocMem(MS_SPT_MAX*MS_BPS, MEMF_ANY)))
  1030.     goto abort;
  1031.  
  1032.     if (!(tdreq = (struct IOExtTD *)
  1033.           CreateExtIO(&unit->mu_DiskReplyPort, (long) sizeof (*tdreq)))) {
  1034.     goto abort;
  1035.     }
  1036.     unit->mu_DiskIOReq = tdreq;
  1037.     if (OpenDevice(TD_NAME, UnitNr, (struct IORequest *)tdreq, TDF_ALLOW_NON_3_5)) {
  1038.     tdreq->iotd_Req.io_Device = NULL;
  1039.     goto abort;
  1040.     }
  1041.     if (tdreq->iotd_Req.io_Device->dd_Library.lib_Version >= SYS2_04)
  1042.     dev->md_System_2_04 = 1;
  1043.  
  1044.     dcr = (void *) CreateExtIO(&unit->mu_DiskReplyPort, (long) sizeof (*dcr));
  1045.     if (dcr) {
  1046.     unit->mu_DiskChangeReq = dcr;
  1047.     unit->mu_DiskChangeInt.is_Node.ln_Pri = 32;
  1048.     unit->mu_DiskChangeInt.is_Data = (APTR) unit;
  1049.     unit->mu_DiskChangeInt.is_Code = (void(*)())DiskChangeHandler;
  1050.     /* Clone IO request part */
  1051.     dcr->io_Device = tdreq->iotd_Req.io_Device;
  1052.     dcr->io_Unit = tdreq->iotd_Req.io_Unit;
  1053.     dcr->io_Command = TD_ADDCHANGEINT;
  1054.     dcr->io_Data = (void *) &unit->mu_DiskChangeInt;
  1055.     SendIO((struct IORequest *)dcr);
  1056.     }
  1057.     NewList((struct List *)&unit->mu_ChangeIntList);
  1058.  
  1059.     unit->mu_NumTracks = TDGetNumTracks(tdreq);
  1060.     unit->mu_UnitNr = UnitNr;
  1061.     unit->mu_OpenFlags = Flags;
  1062.     unit->mu_DiskState = STATEF_UNKNOWN;
  1063.     unit->mu_CurrentTrack = -1;
  1064.     unit->mu_TrackChanged = 0;
  1065.     unit->mu_InitSectorStatus = CRC_UNCHECKED;
  1066.     unit->mu_SectorsPerTrack = MS_SPT;
  1067.     unit->mu_ReadLen = RLEN;
  1068.     unit->mu_WriteLen = WLEN;
  1069.  
  1070.     unit->mu_DRUnit.dru_Message.mn_ReplyPort = &unit->mu_DiskReplyPort;
  1071.     unit->mu_DRUnit.dru_Index.is_Node.ln_Pri = 32; /* high pri for index int */
  1072.     unit->mu_DRUnit.dru_Index.is_Code = IndexIntCode;
  1073.     unit->mu_DRUnit.dru_DiscBlock.is_Code = DskBlkIntCode;
  1074.  
  1075.  
  1076.     /*
  1077.      * Now create the Unit task. Remember that it won't start running
  1078.      * since we are Forbid()den. But just to be sure, we Forbid() again.
  1079.      */
  1080.     Forbid();
  1081.     task = CreateTask(DevName, TASKPRI, UnitTask, TASKSTACK);
  1082.     task->tc_UserData = (APTR) unit;
  1083.  
  1084.     unit->mu_Port.mp_Flags = PA_IGNORE;
  1085.     unit->mu_Port.mp_SigTask = task;
  1086.     NewList(&unit->mu_Port.mp_MsgList);
  1087.  
  1088.     unit->mu_DiskReplyPort.mp_Flags = PA_IGNORE;
  1089.     unit->mu_DiskReplyPort.mp_SigTask = task;
  1090.     NewList(&unit->mu_DiskReplyPort.mp_MsgList);
  1091.     Permit();
  1092.  
  1093. #ifndef READONLY
  1094.     ObtainRawBuffer(dev, unit);
  1095. #endif
  1096.  
  1097.     return unit;
  1098.  
  1099. abort:
  1100.     UnitCloseDown(dev, unit);
  1101.     return NULL;
  1102. }
  1103.  
  1104. int
  1105. UnitCloseDown(dev, unit)
  1106. DEV           *dev;
  1107. REGISTER UNIT  *unit;
  1108. {
  1109.     /*
  1110.      * Get rid of the Unit's task. We know this is safe because the unit
  1111.      * has an open count of zero, so it is 'guaranteed' not in use.
  1112.      */
  1113.  
  1114.     if (unit->mu_Port.mp_SigTask) {
  1115.     debug(("RemTask unit task\n"));
  1116.     /*
  1117.      * The current DICE implementation (2.07.54R) causes MungWall
  1118.      * to complain here, due to non-use of AllocEntry() in the
  1119.      * implementation of CreateTask().
  1120.      */
  1121.     RemTask(unit->mu_Port.mp_SigTask);
  1122.     }
  1123.     if (unit->mu_DiskChangeReq) {
  1124. #if 0                /* V1.2 and V1.3 have a broken
  1125.                  * TD_REMCHANGEINT */
  1126.     REGISTER struct IOExtTD *req = unit->mu_DiskIOReq;
  1127.  
  1128.     req->iotd_Req.io_Command = TD_REMCHANGEINT;
  1129.     req->iotd_Req.io_Data = (void *) unit->mu_DiskChangeReq;
  1130.     DoIO(req);
  1131.     WaitIO(unit->mu_DiskChangeReq);
  1132. #else
  1133.     Disable();
  1134.     Remove(&unit->mu_DiskChangeReq->io_Message.mn_Node);
  1135.     Enable();
  1136. #endif
  1137.     DeleteExtIO((struct IORequest *)unit->mu_DiskChangeReq);
  1138.     unit->mu_DiskChangeReq = NULL;
  1139.     }
  1140.     if (unit->mu_DiskIOReq) {
  1141.     if (unit->mu_DiskIOReq->iotd_Req.io_Device) {
  1142.         debug(("CloseDevice trackdisk\n"));
  1143.         CloseDevice((struct IORequest *)unit->mu_DiskIOReq);
  1144.     }
  1145.     debug(("DeleteExtIO trackdisk io req %x\n", unit->mu_DiskIOReq));
  1146.     DeleteExtIO((struct IORequest *)unit->mu_DiskIOReq);
  1147.     unit->mu_DiskIOReq = NULL;
  1148.     }
  1149.     if (unit->mu_TrackBuffer) {
  1150.     debug(("free TrackBuffer %x\n", unit->mu_TrackBuffer));
  1151.     FreeMem(unit->mu_TrackBuffer, MS_SPT_MAX * MS_BPS);
  1152.     }
  1153.     FreeMem(unit, (long) sizeof (UNIT));
  1154.  
  1155.     return 0;            /* Now unitialized */
  1156. }
  1157.  
  1158. /*
  1159.  * We handle disk change interrupts internally, since the io request is
  1160.  * held by the device. Since SoftInts caused by the trackdisk.device are
  1161.  * broadcast to our clients, our own softint must have the highest
  1162.  * priority possible.
  1163.  *
  1164.  * TD_Addchangeint is an IMMEDIATE command, so no exclusive use of the list
  1165.  * is acquired (nor released). The list is accessed by (software)
  1166.  * interrupt code.
  1167.  */
  1168.  
  1169. void
  1170. TD_Addchangeint(ioreq, unit)
  1171. REGISTER struct IOStdReq *ioreq;
  1172. REGISTER UNIT  *unit;
  1173. {
  1174.     debug(("TD_Addchangeint() entering\n"));
  1175.     Disable();
  1176.     Enqueue((struct List *)&unit->mu_ChangeIntList, &ioreq->io_Message.mn_Node);
  1177.     Enable();
  1178.     ioreq->io_Flags &= ~IOF_QUICK;    /* So we call ReplyMsg instead of
  1179.                      * TermIO */
  1180.     debug(("TD_Addchangeint() done - no TermIO()\n"));
  1181.     /* Note no TermIO */
  1182. }
  1183.  
  1184. void
  1185. TD_Remchangeint(ioreq, unit)
  1186. REGISTER struct IOStdReq *ioreq;
  1187. REGISTER UNIT  *unit;
  1188. {
  1189.     REGISTER struct IOStdReq *intreq;
  1190.  
  1191.     intreq = (struct IOStdReq *) ioreq->io_Data;
  1192.     Disable();
  1193.     Remove(&intreq->io_Message.mn_Node);
  1194.     Enable();
  1195.     ReplyMsg(&intreq->io_Message);    /* Quick bit always cleared */
  1196.     ioreq->io_Error = 0;
  1197.     TermIO(ioreq);
  1198. }
  1199.  
  1200. __geta4 void
  1201. DiskChangeHandler(unit)
  1202. __A1 UNIT      *unit;
  1203. {
  1204.     REGISTER struct IOStdReq *ioreq;
  1205.     REGISTER struct IOStdReq *next;
  1206.  
  1207.     unit->mu_DiskState = STATEF_UNKNOWN;
  1208.     unit->mu_ChangeNum++;
  1209.     unit->mu_SectorsPerTrack = MS_SPT_DD;
  1210. #if 0
  1211.     /*
  1212.      * Theoretically, one should clear the buffer when the disk changes.
  1213.      * However, this makes an ETD_UPDATE go wrong if the disk is changed
  1214.      * and the command retried...
  1215.      * However, above we already reset mu_CurrentSectors...
  1216.      */
  1217.     unit->mu_CurrentTrack = -1;
  1218.     unit->mu_TrackChanged = 0;
  1219. #endif
  1220.     for (ioreq = (struct IOStdReq *) unit->mu_ChangeIntList.mlh_Head;
  1221.      next = (struct IOStdReq *) ioreq->io_Message.mn_Node.ln_Succ;
  1222.      ioreq = next) {
  1223.     Cause((struct Interrupt *) ioreq->io_Data);
  1224.     }
  1225.  
  1226.     WakePort(&unit->mu_Port);
  1227. }
  1228.  
  1229. void
  1230. TD_Getgeometry(ioreq, unit)
  1231. REGISTER struct IOStdReq *ioreq;
  1232. REGISTER UNIT  *unit;
  1233. {
  1234. #ifdef TD_GETGEOMETRY
  1235.     struct DriveGeometry *dg;
  1236.     short numtracks;
  1237.  
  1238.     debug(("TD_Getgeometry\n"));
  1239.     dg = (struct DriveGeometry *)ioreq->io_Data;
  1240.  
  1241.     CheckDriveType(unit);
  1242.     UpdateOpenFlags(ioreq, unit);
  1243.  
  1244.     numtracks = unit->mu_NumTracks;
  1245.     if ((unit->mu_OpenFlags & IOMDF_40TRACKS) &&
  1246.     (numtracks == TRACKS(80))) {
  1247.     numtracks = TRACKS(40);
  1248.     }
  1249.  
  1250.     dg->dg_SectorSize = MS_BPS;
  1251.  
  1252.     dg->dg_TotalSectors = unit->mu_CurrentSectors * numtracks;
  1253.  
  1254.     dg->dg_Cylinders = TRK2CYL(numtracks);
  1255.     dg->dg_CylSectors = unit->mu_CurrentSectors * NUMHEADS;
  1256.  
  1257.     dg->dg_Heads = NUMHEADS;
  1258.     dg->dg_TrackSectors = unit->mu_CurrentSectors;
  1259.  
  1260.     dg->dg_BufMemType = MEMF_PUBLIC;
  1261.     dg->dg_DeviceType = DG_DIRECT_ACCESS;
  1262.     dg->dg_Flags = DGF_REMOVABLE;
  1263. #else
  1264.     debug(("TD_Getgeometry: IOERR_NOCMD\n"));
  1265.     ioreq->io_Error = IOERR_NOCMD;
  1266. #endif
  1267.  
  1268.     TermIO(ioreq);
  1269. }
  1270.  
  1271. #ifndef READONLY
  1272.  
  1273. /*
  1274.  * Parts of the following code were written by Werner Guenther.
  1275.  * Used with permission.
  1276.  */
  1277.  
  1278. /* mu_TrackChanged is a flag. When a sector has changed it changes to 1 */
  1279.  
  1280. /*
  1281.  * ObtainRawBuffer() has to be called before reading or writing
  1282.  * a track. It insures the raw buffer is large enough.
  1283.  */
  1284.  
  1285. int
  1286. ObtainRawBuffer(dev, unit)
  1287. DEV           *dev;
  1288. UNIT           *unit;
  1289. {
  1290.     if (dev->md_Rawbuffer == NULL ||
  1291.     dev->md_RawbufferSize < unit->mu_ReadLen) {
  1292.     FreeRawBuffer(dev);
  1293.  
  1294.     for (;;) {
  1295.         if (dev->md_Rawbuffer =
  1296.             AllocMem((long)unit->mu_ReadLen + 8,
  1297.                   MEMF_CHIP | MEMF_PUBLIC)) {
  1298.         dev->md_RawbufferSize = unit->mu_ReadLen;
  1299.         debug(("ObtainRawBuffer: got %08lx\n", dev->md_Rawbuffer));
  1300.         return 0;
  1301.         }
  1302.         /*
  1303.          * Help! No memory! What to do?
  1304.          * We wait until something happens, such as a disk change
  1305.          * or a new command coming in, and then try again.
  1306.          */
  1307.         debug(("ObtainRawBuffer: no memory\n"));
  1308.         Wait(1L << unit->mu_Port.mp_SigBit);
  1309.     }
  1310.     }
  1311.  
  1312.     return 1;
  1313. }
  1314.  
  1315. /*
  1316.  * FreeRawBuffer has to be called when msh: closes down, it just frees the
  1317.  * memory ObtainRawBuffer has allocated.
  1318.  */
  1319.  
  1320. void
  1321. FreeRawBuffer(dev)
  1322. DEV           *dev;
  1323. {
  1324.     if (dev->md_Rawbuffer) {    /* OIS */
  1325.     debug(("FreeRawBuffer: free %08lx\n", dev->md_Rawbuffer));
  1326.     FreeMem(dev->md_Rawbuffer, dev->md_RawbufferSize + 8);
  1327.     }
  1328. }
  1329.  
  1330. /*
  1331.  * This routine doesn't write to the disk, but updates the TrackBuffer to
  1332.  * respect the new sector. We have to be sure the TrackBuffer is filled
  1333.  * with the current Track. As GetTrack calls Internal_Update if the track
  1334.  * changes we don't have to bother about actually writing any data to the
  1335.  * disk.
  1336.  */
  1337.  
  1338. void
  1339. CMD_Write(ioreq, unit)
  1340. REGISTER struct IOStdReq *ioreq;
  1341. UNIT           *unit;
  1342. {
  1343.     int         track;
  1344.     int         sector;
  1345.     byte       *userbuf;
  1346.     long        length;
  1347.     long        offset;
  1348.     word        spt;
  1349.     int         error;
  1350.  
  1351.     debug(("CMD_Write "));
  1352.     userbuf = (byte *) ioreq->io_Data;
  1353.     length = ioreq->io_Length / MS_BPS;        /* Sector count */
  1354.     offset = ioreq->io_Offset / MS_BPS;        /* Sector number */
  1355.     debug(("userbuf %08lx off %ld len %ld ", userbuf, offset, length));
  1356.  
  1357.     spt = unit->mu_SectorsPerTrack;
  1358.     track = offset / spt;
  1359.     sector = offset % spt;
  1360.     debug(("T=%ld Si=%ld Se=%ld\n", (long)track / MS_NSIDES, (long)track % MS_NSIDES, (long)sector));
  1361.  
  1362.     ioreq->io_Actual = 0;
  1363.  
  1364.     if ((length <= 0) || (error = CheckRequest((struct IOExtTD *)ioreq, unit)))
  1365.     goto end;
  1366.  
  1367.     error = GetTrack(ioreq, track);
  1368.     while (error == TDERR_NoError) {
  1369.     CopyMem(userbuf, unit->mu_TrackBuffer + MS_BPS * sector, (long) MS_BPS);
  1370.     unit->mu_TrackChanged = 1;
  1371.     unit->mu_SectorStatus[sector] = CRC_CHANGED;
  1372.  
  1373.     ioreq->io_Actual += MS_BPS;
  1374.     if (--length <= 0)
  1375.         break;
  1376.     userbuf += MS_BPS;
  1377.     /*
  1378.      * Get next sequential sector/side/track
  1379.      */
  1380.     if (++sector >= spt) {
  1381.         sector = 0;
  1382.         if (++track >= unit->mu_NumTracks) {
  1383.         error = IOERR_BADLENGTH;
  1384.         goto end;
  1385.         }
  1386.         error = GetTrack(ioreq, track);
  1387.     }
  1388.     }
  1389.  
  1390. end:
  1391.     ioreq->io_Error = error;
  1392.     TermIO(ioreq);
  1393. }
  1394.  
  1395. /*
  1396.  * This is called by your GetTrack() routine if the Track has changed. It
  1397.  * writes the changes back to the disk (a whole track at a time).
  1398.  */
  1399.  
  1400. void
  1401. Internal_Update(ioreq, unit)
  1402. struct IOStdReq *ioreq;
  1403. REGISTER UNIT  *unit;
  1404. {
  1405.     debug(("Internal_Update "));
  1406.     /* did we have a changed sector at all     */
  1407.     if (unit->mu_TrackChanged != 0) {
  1408.     debug(("needs to write "));
  1409.  
  1410.     if (unit->mu_SectorsPerTrack > unit->mu_CurrentSectors)
  1411.         unit->mu_CurrentSectors = unit->mu_SectorsPerTrack;
  1412.  
  1413.     /*
  1414.      * Only recalculate the CRC on changed sectors. This way, a
  1415.      * sector with a bad CRC won't suddenly be ``repaired''.
  1416.      */
  1417.     {
  1418.         REGISTER int i;
  1419.  
  1420.         for (i = unit->mu_CurrentSectors - 1; i >= 0; i--) {
  1421.         if (unit->mu_SectorStatus[i] == CRC_CHANGED) {
  1422.             unit->mu_CrcBuffer[i] = DataCRC(unit->mu_TrackBuffer + i * MS_BPS);
  1423.             debug(("%ld: %04lx\n", (long)i, (long)unit->mu_CrcBuffer[i]));
  1424.         }
  1425.         }
  1426.     }
  1427.     {
  1428.         DEV        *dev;
  1429.         REGISTER struct IOExtTD *tdreq;
  1430.         word        SectorGap;
  1431.  
  1432.         dev = (DEV *) ioreq->io_Device;
  1433.         tdreq = unit->mu_DiskIOReq;
  1434.         SectorGap = CalculateGapLength(unit->mu_CurrentSectors);
  1435.  
  1436.         TDMotorOn(tdreq);
  1437.         if (TDSeek(unit, unit->mu_CurrentTrack)) {
  1438.         debug(("Seek error\n"));
  1439.         ioreq->io_Error = TDERR_SeekError;
  1440.         goto end;
  1441.         }
  1442.  
  1443.         ObtainSemaphore(&dev->md_HardwareUse);
  1444.         /*ObtainRawBuffer(dev, unit);*/
  1445.         EncodeTrack(unit->mu_TrackBuffer,
  1446.             dev->md_Rawbuffer,
  1447.             unit->mu_CrcBuffer,
  1448.             TRK2CYL(unit->mu_CurrentTrack),  /* cylinder */
  1449.             TRK2SIDE(unit->mu_CurrentTrack), /* side */
  1450.             SectorGap,
  1451.             unit->mu_CurrentSectors,
  1452.             unit->mu_WriteLen);
  1453.  
  1454.         HardwareWrite(dev, unit, ioreq);
  1455.  
  1456.         ReleaseSemaphore(&dev->md_HardwareUse);
  1457.         unit->mu_TrackChanged = 0;
  1458.     }
  1459.     }
  1460. end:
  1461.     debug(("done\n"));
  1462. }
  1463.  
  1464. /*
  1465.  * TD_Format writes one or more whole tracks without reading them first.
  1466.  */
  1467.  
  1468. void
  1469. TD_Format(ioreq, unit)
  1470. REGISTER struct IOStdReq *ioreq;
  1471. UNIT           *unit;
  1472. {
  1473.     REGISTER struct IOExtTD *tdreq = unit->mu_DiskIOReq;
  1474.     DEV        *dev;
  1475.     int         track;
  1476.     byte       *userbuf;
  1477.     int         length;
  1478.     word        spt;
  1479.     word        gaplen;
  1480.  
  1481.     debug(("CMD_Format "));
  1482.  
  1483.     if (CheckRequest((struct IOExtTD *)ioreq, unit))
  1484.     goto termio;
  1485.  
  1486.     userbuf = (byte *) ioreq->io_Data;
  1487.     length = ioreq->io_Length / MS_BPS;        /* Sector count */
  1488.     track = ioreq->io_Offset / MS_BPS;           /* Sector number */
  1489.     /*
  1490.      * Now try to guess the number of sectors the user wants per track.
  1491.      * The existence of high-density floppies muddies the water
  1492.      * considerably.
  1493.      * With 40 sectors there is ambiguity: 5 * 8 or 4 * 10.
  1494.      */
  1495.     if (track != 0)
  1496.     spt = unit->mu_SectorsPerTrack;
  1497.     else if (length <= 80) {
  1498.     if (length > 0) {
  1499.         int         low, high;
  1500.  
  1501.         if (unit->mu_DiskState & STATEF_HIGHDENSITY) {
  1502.         if (length <= MS_SPT_MAX_HD) {
  1503.             spt = length;
  1504.             goto found_spt;
  1505.         }
  1506.         low = 15;
  1507.         high = MS_SPT_MAX_HD;
  1508.         } else {
  1509.         if (length <= MS_SPT_MAX_DD) {
  1510.             spt = length;
  1511.             goto found_spt;
  1512.         } else if (length == 40) {
  1513.             /* solve ambiguity in most desirable? way */
  1514.             spt = 10;
  1515.             goto found_spt;
  1516.         }
  1517.         low = 8;
  1518.         high = MS_SPT_MAX_DD;
  1519.         }
  1520.         for (spt = low; spt <= high; spt++) {
  1521.         if ((length % spt) == 0)
  1522.             goto found_spt;
  1523.         }
  1524.     }
  1525.     /*
  1526.      * The following values are OK:
  1527.      *
  1528.      * DD: 8, 16, 24, 32, 40, 48, 56, 64
  1529.      *     9, 18, 27, 36, 45, 54, 63, 72
  1530.      *    10, 20, 30, 40, 50, 60, 70, 80
  1531.      *
  1532.      * HD:15, 30, 45, 60
  1533.      *    16, 32, 48, 64
  1534.      *    17, 34, 51, 68
  1535.      *    18, 36, 54, 72
  1536.      *    19, 38, 57, 76
  1537.      *    20, 40, 60, 80
  1538.      *    21, 42, 63
  1539.      */
  1540.     ioreq->io_Error = IOERR_BADLENGTH;
  1541.     goto termio;
  1542.     } else  /* assume previous number */
  1543.     spt = unit->mu_SectorsPerTrack;
  1544.  
  1545. found_spt:
  1546.     debug(("%d sectors/track\n", spt));
  1547.     gaplen = CalculateGapLength(spt);
  1548.  
  1549.     /*
  1550.      * Assume the whole disk will have this layout.
  1551.      */
  1552.     unit->mu_SectorsPerTrack = spt;
  1553.  
  1554.     length /= spt;        /* convert to number of tracks */
  1555.     track /= spt;        /* convert to track number */
  1556.  
  1557.     debug(("userbuf %08lx track %ld len %ld\n", userbuf, (long)track, (long)length));
  1558.  
  1559.     ioreq->io_Actual = 0;
  1560.  
  1561.     /*
  1562.      * Write out the current track if we are not going to overwrite it.
  1563.      * After the format operation, the buffer is invalidated.
  1564.      */
  1565.     if (track <= unit->mu_CurrentTrack &&
  1566.          unit->mu_CurrentTrack < track + length)
  1567.     Internal_Update(ioreq, unit);
  1568.  
  1569.     dev = (DEV *) ioreq->io_Device;
  1570.  
  1571.     while (length > 0) {
  1572.     {
  1573.         REGISTER int i;
  1574.  
  1575.         for (i = spt - 1; i >= 0; i--) {
  1576.         unit->mu_CrcBuffer[i] = DataCRC(userbuf + i * MS_BPS);
  1577.         debug(("%ld: %04x\n", (long)i, unit->mu_CrcBuffer[i]));
  1578.         }
  1579.     }
  1580.     ObtainSemaphore(&dev->md_HardwareUse);
  1581.     ObtainRawBuffer(dev, unit);
  1582.     EncodeTrack(userbuf,
  1583.             dev->md_Rawbuffer,
  1584.             unit->mu_CrcBuffer,
  1585.             TRK2CYL(track),    /* cylinder */
  1586.             TRK2SIDE(track),    /* side */
  1587.             gaplen,
  1588.             spt,
  1589.             unit->mu_WriteLen);
  1590.  
  1591.     TDMotorOn(tdreq);
  1592.     if (TDSeek(unit, track)) {
  1593.         debug(("Seek error\n"));
  1594.         ioreq->io_Error = IOERR_BADLENGTH;
  1595.         break;
  1596.     }
  1597.     unit->mu_CurrentTrack = track;
  1598.     HardwareWrite(dev, unit, ioreq);
  1599.  
  1600.     ReleaseSemaphore(&dev->md_HardwareUse);
  1601.  
  1602.     length--;
  1603.     userbuf += MS_BPS * spt;
  1604.     ioreq->io_Actual += MS_BPS * spt;
  1605.  
  1606.     if (++track >= unit->mu_NumTracks)
  1607.         goto end;
  1608.     }
  1609. end:
  1610.     unit->mu_CurrentTrack = -1;
  1611.     unit->mu_TrackChanged = 0;
  1612. termio:
  1613.     TermIO(ioreq);
  1614. }
  1615.  
  1616. #endif /* READONLY */
  1617.